-------------------------------------------------------------------
--                    AmB Ref Function                           --
-------------------------------------------------------------------

-- (This function is so awesome, it deserves to be global)
-- Creates a reference to the key on the specified table. When
-- the table is changed, the ref will be updated. The value returned
-- by this function will be linked to the table.
-- Okay, you dont understand do you.
-- EXAMPLE TIME!
---- table = { }
---- table.MyNum = 9
---- x = table.MyNum
---- print(x)
---- table.MyNum = 10
---- print(x)
-- OH SHI- it prints 9 twice.
-- Wonder what happens when i use this?
---- table = { }
---- table.MyNum = 9
---- x = Ref(table, "MyNum")
---- print(x)
---- table.MyNum = 10
---- print(x)
-- Awesome, it prints 9 and 10. This means, if table
-- is changed, ref is changed with it.
function Ref(Table, Key)
	local r = { _Table = Table, _Key = Key }
	local mt = { }
	
	local function val(a)
		return rawget(a, "_Table")[rawget(a, "_Key")]
	end
	
	local function binop(a, b, f)
		if type(a) == "table" then
			a = val(a) or a
		end
		if type(b) == "table" then
			b = val(b) or b
		end
		return f(a, b)
	end
	
	-- Index/newindex
	function mt.__index(t, k) return val(t)[k] end
	function mt.__newindex(t, k, v) val(t)[k] = v end
	
	-- Loads of binary ops.
	function mt.__add(a, b) return binop(a, b, function(a, b) return a + b end) end
	function mt.__sub(a, b) return binop(a, b, function(a, b) return a - b end) end
	function mt.__mul(a, b) return binop(a, b, function(a, b) return a * b end) end
	function mt.__div(a, b) return binop(a, b, function(a, b) return a / b end) end
	function mt.__mod(a, b) return binop(a, b, function(a, b) return a % b end) end
	function mt.__pow(a, b) return binop(a, b, function(a, b) return a ^ b end) end
	function mt.__concat(a, b) return binop(a, b, function(a, b) return a .. b end) end
	function mt.__eq(a, b) return binop(a, b, function(a, b) return a == b end) end
	function mt.__lt(a, b) return binop(a, b, function(a, b) return a < b end) end
	function mt.__gt(a, b) return binop(a, b, function(a, b) return a > b end) end
	
	-- Single argument ops
	function mt.__unm(a) return -(val(a)) end
	function mt.__len(a) return #(val(a)) end
	
	-- Varidaic argument ops
	function mt.__call(a, ...) return (val(a))(...) end
	
	setmetatable(r, mt)
	return r
end

-- Hokay, so, you got this reference and you want to use
-- it on a long piece of code, but you know it must not
-- change in that time. Use this function to get its value at
-- the moment. 
-- This is also useful if you are calling an outside function(that
-- is not completely retarded and will actually check if the
-- input is a table) as it gets the actually value of the
-- reference.
-- IT IS SAFE TO FREEZE A NONREF
function Freeze(Ref)
	if type(Ref) == "table" and getmetatable(Ref) != nil then
		local t = rawget(Ref, "_Table")
		if t != nil then
			k = rawget(Ref, "_Key")
			if k != nil then
				return Freeze(t[k])
			end
		end
	end
	return Ref
end

-- Ehh, just incase the globalness of the function doesnt
-- go through.
AmB.Ref = Ref
AmB.Freeze = Freeze